移动端Tap事件学习

# [从移动端 click 到摇一摇]
以前听到前辈们说移动端尽量不要使用click,click会比较迟钝,能用touchstart还是用touchstart。但是用touchstart会有一个问题,用户在滑动页面的时候要是不小心碰到了相关元素也会触发touchstart,所以两者都有缺点。那怎么办呢?

首先为什么移动端的click会迟钝呢?从谷歌的开发者文档《300ms tap delay, gone away》可以找到答案:
大意是说因为移动端要判断是否是双击,所以单击之后不能够立刻触发click,要等300ms,直到确认不是双击了才触发click。所以就导致了click有延迟。

### 1
更为重要的是,文档里面还提到在2014年的Chrome 32版本已经把这个延迟去掉了,如果有一个meta标签:<meta name="viewport" content="width=device-width">
即把viewport设置成设备的实际像素,那么就不会有这300ms的延迟,并且这个举动受到了IE/Firefox/Safari(IOS 9.3)的支持,也就是说现在的移动端开发可以不用顾虑click会比较迟钝的问题。

### 2
如果设置initial-scale=1.0,在chrome上是可以生效,但是Safari不会:
<meta name="viewport" content="initial-scale=1.0">

### 3
还有第三种办法就是设置CSS:
html{touch-action:manipulation;}
这样也可以取消掉300ms的延迟,Chrome和Safari都可以生效。

1. click/touch触发顺序

1. 可以看到click事件是在最后触发的,并且还看到300ms的延迟,实际的执行延迟要比这个大,因为浏览器的内核运行也需要消耗时间。

2. 现在加上viewport的meta标签,再观察结果,如下图所示:
可以看到,300ms的延迟没有了。

知道了click是在touchend之后触发的,现在我们来尝试一下实现一个tap事件。

2. tap事件的实现

一个是zepto,另一个是fastclick
zepto有一个自定义事件tap,它是一个没有延迟的click事件。
而fastclick是在touchend之后生成一个click事件,并立即触发这个click,再取消原本的click事件。

这两者的原理都是一样的,都是在touchend之后触发,一个是触发它自己定义的tap事件,一个是触发原生click。

所以怎么判定用户是点击还是在上下滑呢?
Zepto是用的位移偏差, 如果这个差值在30以内
而fastclick是用的时间偏差,分别记录touchstart和touchend的时间戳,如果它们的时间差大于700毫秒,
Chromium的源码,它里面封装了一些移动端的手势实现如tap,tap是根据时间位移判断是否要触发tap,

3. 摇一摇事件

html5新增了一个devicemotion的事件,可以使用手机的重力感应。如下代码所示:
window.ondevicemotion=function(event){
vargravity=event.accelerationIncludingGravity;
console.log(gravity.x,gravity.y,gravity.z);
}
当然判断是否摇一摇的算法不止上面一个,你还可以想出其它更好的方法。

十行代码实现的studiotap事件

$_PS: 十行代码自定义移动端tap事件,看源码感觉哪里有些不对:hasClass是什么鬼

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// # Z 十行代码自定义移动端tap事件
$$(document).on("touchstart", function(e) {
if(!$$(e.target).hasClass("disable"))
$$(e.target).data("isMoved", 0);
});
$$(document).on("touchmove", function(e) {
if(!$$(e.target).hasClass("disable"))
$$(e.target).data("isMoved", 1);
});
$$(document).on("touchend", function(e) {
if(!$$(e.target).hasClass("disable") && $$(e.target).data("isMoved") == 0)
$$(e.target).trigger("tap");
});

// # 使用
// ? but,ipad中click事件会延迟200ms 触发, 同时还触发了tap
// 还要防止videojs中的冒泡事件
$$('#div_video').on('click tap',function(e){
e=e||event;// for chrome which is diff from firefox
if(e.target.parentElement.parentElement==this){

}
});

knowledge is no pay,reward is kindness
0%